package uml2Java;

import java.util.Map;

import org.eclipse.emf.common.util.EList;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.VisibilityKind;

import astjava.BodyDeclaration;
import astjava.ClassDeclaration;
import astjava.InheritanceKind;
import astjava.InterfaceDeclaration;
import astjava.JavaFactory;
import astjava.SingleVariableDeclaration;

public class TransformMethods {

	private Package _umlPackage; 
	
	private Map<String, astjava.Type> _symbolMap;
	
	private TransformPackagesAndTypes _transformerTypes;

	public TransformMethods(TransformPackagesAndTypes transformerTypes) {
		_umlPackage = transformerTypes.get_umlPackage();
		_symbolMap = transformerTypes.get_symbolMap();
		_transformerTypes = transformerTypes;
	}

	public void doTransformMethods() {
		EList<Type> umlTypes = _umlPackage.getOwnedTypes();
		for (Type umlType : umlTypes) {
			if (umlType instanceof Interface) {
				Interface umlInterface = (Interface) umlType;
				InterfaceDeclaration javaInterface = (InterfaceDeclaration) _symbolMap.get(umlInterface.getName());
				for (Operation umlOperation : umlInterface.getOwnedOperations()) {
					try {
						validateOperationInInterface(umlOperation);
						javaInterface.getBodyDeclarations().add(transformOperation(umlOperation));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
			if (umlType instanceof Class) {
				Class umlClass = (Class) umlType;
				ClassDeclaration javaClass = (ClassDeclaration) _symbolMap.get(umlClass.getName());
				for (Operation umlOperation : umlClass.getOwnedOperations()) 
					javaClass.getBodyDeclarations().add(transformOperation(umlOperation));	
			}
		}
	}
	
	private BodyDeclaration transformOperation(Operation umlOperation) {
		astjava.MethodDeclaration methodJava = JavaFactory.eINSTANCE.createMethodDeclaration();
		methodJava.setName(umlOperation.getName());
		methodJava.setModifier(JavaFactory.eINSTANCE.createModifier());
		methodJava.getModifier().setVisibility(_transformerTypes.transformVisibility(umlOperation.getVisibility()));
		methodJava.getModifier().setStatic(umlOperation.isStatic());
		if (umlOperation.isAbstract())
			methodJava.getModifier().setInheritance(InheritanceKind.ABSTRACT);
		methodJava.setReturnType(JavaFactory.eINSTANCE.createTypeAccess());
		if (umlOperation.getType() == null) 
			methodJava.getReturnType().setType(_symbolMap.get("EVoid"));
		else
			methodJava.getReturnType().setType(_symbolMap.get(umlOperation.getType().getName()));
		for (Parameter umlParameter : umlOperation.getOwnedParameters()) {
			if (!umlParameter.getDirection().equals(ParameterDirectionKind.RETURN_LITERAL)) {
				methodJava.getParameters().add(transformParameter(umlParameter));
			}
		}
		return methodJava;
	}

	private SingleVariableDeclaration transformParameter(Parameter umlParameter) {
		SingleVariableDeclaration javaParametre = JavaFactory.eINSTANCE.createSingleVariableDeclaration();
		javaParametre.setName(umlParameter.getName());
		javaParametre.setType(JavaFactory.eINSTANCE.createTypeAccess());
		javaParametre.getType().setType(_symbolMap.get(umlParameter.getType().getName()));
		return javaParametre;
	}

	private void validateOperationInInterface(Operation operation) throws IllegalVisibityException, NonStaticOperationException {
		if (operation.isStatic()) {
			throw new NonStaticOperationException(operation);
		}
		if (operation.getVisibility().equals(VisibilityKind.PRIVATE_LITERAL) ||
				operation.getVisibility().equals(VisibilityKind.PROTECTED_LITERAL)) {
			throw new IllegalVisibityException(operation);
		}
	}
}
